package com.mapforge.gui.map;

import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;

import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.Scrollable;
import javax.swing.SwingConstants;

import com.mapforge.map.Tileset;

/**
 * A panel which displays a tileset.
 * 
 * @author BoogeyMan the Great
 * 
 */
public class TilesetPanel extends JLabel implements Scrollable {

	/**
	 * Default serial version ID, here to remove warnings
	 */
	private static final long serialVersionUID = 1L;
	private int maxUnitIncrement = 1;

	/**
	 * Tileset this panel is rendering
	 */
	private Tileset tileset;

	public TilesetPanel() {
		this(null, null);
	}

	public TilesetPanel(Tileset tileset, BufferedImage fullTilesetImage) {
		super();
		if (fullTilesetImage == null || tileset == null) {
			setText("No picture found.");
			setHorizontalAlignment(CENTER);
			setOpaque(true);
		} else {
			setOpaque(false);
			maxUnitIncrement = Math.max(tileset.getTileWidth(), tileset
					.getTileHeight());
			setIcon(new ImageIcon(fullTilesetImage));
		}
		// Let the user scroll by dragging to outside the window.
		setAutoscrolls(true);
		// handles mouse drags
		addMouseMotionListener(new TilesetPanelScrollListener());
	}

	public Dimension getPreferredSize() {
		if (tileset != null) {
			return new Dimension(tileset.getTilesetImageWidth()+1, tileset
					.getTilesetImageHeight()+1);
		} else {
			return super.getPreferredSize();
		}
	}

	public Dimension getPreferredScrollableViewportSize() {
		return getPreferredSize();
	}

	public int getScrollableUnitIncrement(Rectangle visibleRect,
			int orientation, int direction) {
		// Get the current position.
		int currentPosition = 0;
		if (orientation == SwingConstants.HORIZONTAL) {
			currentPosition = visibleRect.x;
		} else {
			currentPosition = visibleRect.y;
		}

		// Return the number of pixels between currentPosition
		// and the nearest tick mark in the indicated direction.
		if (direction < 0) {
			int newPosition = currentPosition
					- (currentPosition / maxUnitIncrement) * maxUnitIncrement;
			return (newPosition == 0) ? maxUnitIncrement : newPosition;
		} else {
			return ((currentPosition / maxUnitIncrement) + 1)
					* maxUnitIncrement - currentPosition;
		}
	}

	public int getScrollableBlockIncrement(Rectangle visibleRect,
			int orientation, int direction) {
		if (orientation == SwingConstants.HORIZONTAL) {
			return visibleRect.width - maxUnitIncrement;
		} else {
			return visibleRect.height - maxUnitIncrement;
		}
	}

	public boolean getScrollableTracksViewportWidth() {
		return false;
	}

	public boolean getScrollableTracksViewportHeight() {
		return false;
	}

	public void setMaxUnitIncrement(int pixels) {
		maxUnitIncrement = pixels;
	}

	public void setTileset(Tileset tileset, BufferedImage fullTilesetImage) {
		this.tileset = tileset;
		if (fullTilesetImage != null) {
			setPreferredSize(new Dimension(fullTilesetImage.getWidth()+1,
					fullTilesetImage.getHeight()+1));
			setIcon(new ImageIcon(fullTilesetImage));
			setText("");
			setOpaque(false);
			revalidate();
			repaint();
		} else {
			setText("No picture found.");
			setHorizontalAlignment(CENTER);
			setOpaque(true);
			revalidate();
			repaint();
		}
	}

	public Tileset getTileset() {
		return tileset;
	}

	public void removeTileset() {
		this.tileset = null;
		setPreferredSize(new Dimension(0, 0));
		revalidate();
	}

	private class TilesetPanelScrollListener implements MouseMotionListener {

		// Methods required by the MouseMotionListener interface:
		public void mouseMoved(MouseEvent e) {
		}

		public void mouseDragged(MouseEvent e) {
			// The user is dragging us, so scroll!
			Rectangle r = new Rectangle(e.getX(), e.getY(), 1, 1);
			scrollRectToVisible(r);
		}
	}
}
